﻿using HalconDotNet;
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;

namespace DetectApp.Display;

public class ArcControl : ROIControl
{
    private readonly Canvas _canvas;
    private Path _arcPath;
    private ArcSegment _arcSegment;
    private PathFigure _pathFigure;
    private readonly List<Shape> _docEllipse = new();
    public double K { get => _canvas.ActualWidth / 500.0; }
    private int _docDiameter = 0;
    private double _initRadius = 50;
    private bool _isMove;
    private bool _isSCale1;
    private bool _isSCale2;
    private bool _isSCale3;
    private bool _isSCale4;
    private bool _isRotate;
    private Point _startPoint;
    private double _circleRad;
    private Point _circleCenter;
    private double _startTopLeft;
    private double _startTopUp;
    private double _startAngle;
    private Point _circleEndPoint;
    private Point _circleStartPoint;

    public ArcControl(Canvas canvas, Color color)
    {
        _canvas = canvas;
        _arcSegment = new()
        {
            Point = new(50 + _initRadius * K * 2, 50),
            Size = new Size { Width = _initRadius * K, Height = _initRadius * K },
            IsLargeArc = false,
            SweepDirection = SweepDirection.Counterclockwise,
        };
        _pathFigure = new()
        {
            StartPoint = new(50, 50),
            IsClosed = false,
            IsFilled = true,
        };
        _pathFigure.Segments.Add(_arcSegment);
        PathGeometry pathGeometry = new();
        pathGeometry.Figures.Add(_pathFigure);
        _arcPath = new()
        {
            Fill = new SolidColorBrush(Colors.Red) { Opacity = 0.1 },
            Stroke = new SolidColorBrush(color),
            StrokeThickness = 1 * K,
            Data = pathGeometry,
        };
        _arcPath.MouseEnter += (s, e) =>
        {
            UpdateEllipse(_arcPath, _canvas);
        };
        _circleCenter.X = (100 + _initRadius * K * 2) / 2;
        _circleCenter.Y = 50;

        _canvas.Children.Add(_arcPath);
        _canvas.MouseLeftButtonDown += CurPath_MouseLeftButtonDown;
        _canvas.MouseMove += Canvas_MouseMove;
        Canvas.SetLeft(_arcPath, _canvas.ActualWidth / 2 - _initRadius * K / 2);
        Canvas.SetTop(_arcPath, _canvas.ActualHeight / 2 - _initRadius * K / 2);
        ROIChange?.Invoke(this, EventArgs.Empty);
    }

    public ArcControl(Canvas canvas, ROIParam param)
    {
        _canvas = canvas;
        _arcSegment = new()
        {
            Point = param.arc_end,
            Size = new Size { Width = param.arc_width, Height = param.arc_height },
            IsLargeArc = false,
            SweepDirection = SweepDirection.Counterclockwise,
        };
        _pathFigure = new()
        {
            StartPoint = param.arc_start,
            IsClosed = false,
            IsFilled = true,
        };
        _pathFigure.Segments.Add(_arcSegment);
        PathGeometry pathGeometry = new();
        pathGeometry.Figures.Add(_pathFigure);
        _arcPath = new()
        {
            Fill = new SolidColorBrush(Colors.Red) { Opacity = 0.1 },
            Stroke = new SolidColorBrush(Colors.Blue),
            StrokeThickness = 1 * K,
            Data = pathGeometry,
        };
        _arcPath.MouseEnter += (s, e) =>
        {
            UpdateEllipse(_arcPath, _canvas);
        };
        _circleCenter.X = (100 + _initRadius * K * 2) / 2;
        _circleCenter.Y = 50;

        _canvas.Children.Add(_arcPath);
        _canvas.MouseLeftButtonDown += CurPath_MouseLeftButtonDown;
        _canvas.MouseMove += Canvas_MouseMove;
        Canvas.SetLeft(_arcPath, param.Left);
        Canvas.SetTop(_arcPath, param.Top);
        ROIChange?.Invoke(this, EventArgs.Empty);
    }

    private void Canvas_MouseMove(object sender, MouseEventArgs e)
    {
        if (Mouse.LeftButton == MouseButtonState.Released)
        {
            _isMove = false; _isSCale1 = false; _isSCale2 = false; _isSCale3 = false; _isSCale4 = false; _isRotate = false;
        }
        if (!_isSCale1 & !_isSCale2 & !_isSCale3 & !_isSCale4 & !_isMove & !_isRotate)
        {
            bool isClear = true;
            if (_arcPath.IsMouseOver == true) { isClear = false; }
            foreach (var rect in _docEllipse)
            {
                if (rect.IsMouseOver)
                {
                    isClear = false;
                    break;
                }
            }
            if (isClear)
            {
                _docEllipse.ForEach(e => { _canvas.Children.Remove(e); });
                _docEllipse.Clear();
            };
        }
        if (_isMove)
        {
            Point curPoint = Mouse.GetPosition(_canvas);
            var rPoint = curPoint - _startPoint;
            Canvas.SetLeft(_arcPath, _startTopLeft + rPoint.X);
            Canvas.SetTop(_arcPath, _startTopUp + rPoint.Y);
            UpdateEllipse(_arcPath, _canvas);
            ROIChange?.Invoke(this, EventArgs.Empty);
        }
        if (_isSCale1)
        {
            Point endPoint = Mouse.GetPosition(_arcPath);
            double angle = Math.Atan2(endPoint.Y - _circleCenter.Y, endPoint.X - _circleCenter.X);
            double ra = angle - _startAngle;
            double x = (_startPoint.X - _circleCenter.X) * Math.Cos(ra) - (_startPoint.Y - _circleCenter.Y) * Math.Sin(ra) + _circleCenter.X;
            double y = (_startPoint.X - _circleCenter.X) * Math.Sin(ra) + (_startPoint.Y - _circleCenter.Y) * Math.Cos(ra) + _circleCenter.Y;
            _pathFigure.StartPoint = new Point(x, y);
            HOperatorSet.AngleLl(y, x, _circleCenter.Y, _circleCenter.X, _arcSegment.Point.Y, _arcSegment.Point.X, _circleCenter.Y, _circleCenter.X, out HTuple angle1);
            if (angle1 < 0)
                _arcSegment.IsLargeArc = true;
            else _arcSegment.IsLargeArc = false;
            UpdateEllipse(_arcPath, _canvas);
            ROIChange?.Invoke(this, EventArgs.Empty);
        }
        if (_isSCale2)
        {
            Point endPoint = Mouse.GetPosition(_arcPath);
            double angle = Math.Atan2(endPoint.Y - _circleCenter.Y, endPoint.X - _circleCenter.X);
            double ra = angle - _startAngle;
            double x = (_startPoint.X - _circleCenter.X) * Math.Cos(ra) - (_startPoint.Y - _circleCenter.Y) * Math.Sin(ra) + _circleCenter.X;
            double y = (_startPoint.X - _circleCenter.X) * Math.Sin(ra) + (_startPoint.Y - _circleCenter.Y) * Math.Cos(ra) + _circleCenter.Y;
            _arcSegment.Point = new Point(x, y);
            HOperatorSet.AngleLl(_pathFigure.StartPoint.Y, _pathFigure.StartPoint.X, _circleCenter.Y, _circleCenter.X, _arcSegment.Point.Y, _arcSegment.Point.X, _circleCenter.Y, _circleCenter.X, out HTuple angle1);
            if (angle1 < 0)
                _arcSegment.IsLargeArc = true;
            else _arcSegment.IsLargeArc = false;
            UpdateEllipse(_arcPath, _canvas);
            ROIChange?.Invoke(this, EventArgs.Empty);
        }
        if (_isSCale3)
        {
            Point endPoint = Mouse.GetPosition(_arcPath);
            HOperatorSet.DistancePp(_circleCenter.Y, _circleCenter.X, endPoint.Y, endPoint.X, out HTuple distance);
            _arcSegment.Size = new Size() { Width = distance, Height = distance };
            double rb = (distance) / _circleRad;
            _pathFigure.StartPoint = new Point((_circleStartPoint.X - _circleCenter.X) * rb + _circleCenter.X, (_circleStartPoint.Y - _circleCenter.Y) * rb + _circleCenter.Y);
            _arcSegment.Point = new Point((_circleEndPoint.X - _circleCenter.X) * rb + _circleCenter.X, (_circleEndPoint.Y - _circleCenter.Y) * rb + _circleCenter.Y);
            UpdateEllipse(_arcPath, _canvas);
            ROIChange?.Invoke(this, EventArgs.Empty);
        }
    }

    private void CurPath_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        if (_arcPath.IsMouseOver)
        {
            _isMove = true;
            _startPoint = Mouse.GetPosition(_canvas);
            _startTopUp = Canvas.GetTop(_arcPath);
            _startTopLeft = Canvas.GetLeft(_arcPath);
        }
    }

    private void UpdateEllipse(Path path, Canvas canvas)
    {
        //ROIChange?.Invoke(this, EventArgs.Empty);
        _docDiameter = (int)(5 * K);
        Brush fillBrush = new SolidColorBrush(Colors.Blue);
        double opacityK = 1;
        _docEllipse.ForEach(e => { canvas.Children.Remove(e); });
        _docEllipse.Clear();
        Point point = _arcPath.TranslatePoint(new Point(_pathFigure.StartPoint.X, _pathFigure.StartPoint.Y), canvas);
        Ellipse circle1 = new() { Width = _docDiameter, Height = _docDiameter, Fill = fillBrush, Opacity = opacityK };
        Canvas.SetLeft(circle1, point.X - _docDiameter / 2);
        Canvas.SetTop(circle1, point.Y - _docDiameter / 2);
        canvas.Children.Add(circle1);
        _docEllipse.Add(circle1);

        circle1.MouseLeftButtonDown += (s, e) =>
        {
            _isSCale1 = true;
            _startPoint = _pathFigure.StartPoint;
            _startAngle = Math.Atan2(_startPoint.Y - _circleCenter.Y, _startPoint.X - _circleCenter.X);
        };
        circle1.MouseLeftButtonUp += (s, e) => { _isSCale1 = false; };

        point = _arcPath.TranslatePoint(new Point(_arcSegment.Point.X, _arcSegment.Point.Y), canvas);
        Ellipse circle2 = new() { Width = _docDiameter, Height = _docDiameter, Fill = fillBrush, Opacity = opacityK };
        Canvas.SetLeft(circle2, point.X - _docDiameter / 2);
        Canvas.SetTop(circle2, point.Y - _docDiameter / 2);
        canvas.Children.Add(circle2);
        _docEllipse.Add(circle2);
        circle2.MouseLeftButtonDown += (s, e) =>
        {
            _isSCale2 = true;
            _startPoint = _arcSegment.Point;
            _startAngle = Math.Atan2(_startPoint.Y - _circleCenter.Y, _startPoint.X - _circleCenter.X);
        };
        circle2.MouseLeftButtonUp += (s, e) => { _isSCale2 = false; };

        HOperatorSet.AngleLl(_circleCenter.Y, _circleCenter.X, _pathFigure.StartPoint.Y, _pathFigure.StartPoint.X, _circleCenter.Y, _circleCenter.X, _arcSegment.Point.Y, _arcSegment.Point.X, out HTuple angle);
        if (_arcSegment.IsLargeArc) { angle = angle - 2 * Math.PI; }
        double x = (_pathFigure.StartPoint.X - _circleCenter.X) * Math.Cos(-angle / 2) - (_pathFigure.StartPoint.Y - _circleCenter.Y) * Math.Sin(-angle / 2) + _circleCenter.X;
        double y = (_pathFigure.StartPoint.X - _circleCenter.X) * Math.Sin(-angle / 2) + (_pathFigure.StartPoint.Y - _circleCenter.Y) * Math.Cos(-angle / 2) + _circleCenter.Y;
        point = _arcPath.TranslatePoint(new Point(x, y), canvas);
        Ellipse circle3 = new() { Width = _docDiameter, Height = _docDiameter, Fill = fillBrush, Opacity = opacityK };
        Canvas.SetLeft(circle3, point.X - _docDiameter / 2);
        Canvas.SetTop(circle3, point.Y - _docDiameter / 2);
        canvas.Children.Add(circle3);
        _docEllipse.Add(circle3);
        circle3.MouseLeftButtonDown += (s, e) =>
        {
            _isSCale3 = true;
            _startPoint = e.GetPosition(canvas);
            _circleRad = _arcSegment.Size.Width;
            _circleStartPoint = _pathFigure.StartPoint;
            _circleEndPoint = _arcSegment.Point;
        };
        circle3.MouseLeftButtonUp += (s, e) => { _isSCale3 = false; };
    }

    public override ROIParam GetParam()
    {
        ROIParam roi = new() { ROIType = ROIType.圆弧 };
        roi.arc_start = _pathFigure.StartPoint;
        roi.arc_end = _arcSegment.Point;
        roi.arc_width = _arcSegment.Size.Width;
        roi.arc_height = _arcSegment.Size.Height;
        roi.Left = Canvas.GetLeft(_arcPath);
        roi.Top = Canvas.GetTop(_arcPath);
        return roi;
    }

    public override HRegion? GetRegion()
    {
        return null;
    }

    public override ROIInfo GetROI()
    {
        ROIInfo roi = new();
        roi.ROIType = ROIType.圆弧;
        Point point = _arcPath.TranslatePoint(new Point { X = 50 + _initRadius * K, Y = 50 }, _canvas);
        roi.CircleX = point.X;
        roi.CircleY = point.Y;
        roi.Radius = _arcSegment.Size.Width;
        Point startPoint = _arcPath.TranslatePoint(_pathFigure.StartPoint, _canvas);
        roi.StartAngle = Math.Atan2(point.Y - startPoint.Y, startPoint.X - point.X);
        roi.EndAngle = Math.Atan2(50 - _arcSegment.Point.Y, _arcSegment.Point.X - 50 - _initRadius * K);
        roi.SweepDirection = _arcSegment.SweepDirection;
        return roi;
    }

    public override void Remove()
    {
        _canvas.Children.Remove(_arcPath);
    }
}